package com.security.demo.codefilter;

import com.security.demo.code.ImageCode;
import com.security.demo.exception.ValidateCodeException;
import com.security.demo.properties.SecurityProperties;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static com.security.demo.controller.ValidateCodeController.SESSION_KEY;

/**
 * @author td
 * @date 2017/10/27
 */
public class ValidateCodeFilter extends OncePerRequestFilter {

    private SecurityProperties securityProperties;

    private AuthenticationFailureHandler myAuthenticationFailHandler;

    private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();

    public SecurityProperties getSecurityProperties() {
        return securityProperties;
    }

    public void setSecurityProperties(SecurityProperties securityProperties) {
        this.securityProperties = securityProperties;
    }

    public AuthenticationFailureHandler getMyAuthenticationFailHandler() {
        return myAuthenticationFailHandler;
    }

    public void setMyAuthenticationFailHandler(AuthenticationFailureHandler myAuthenticationFailHandler) {
        this.myAuthenticationFailHandler = myAuthenticationFailHandler;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {

        // 进行验证验证码
        if (StringUtils.equals("/authentication/form",httpServletRequest.getRequestURI())
                &&StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(),"POST")) {
            // 是登录请求，进行验证码验证
            try {
                validate(new ServletWebRequest(httpServletRequest));
            } catch (ValidateCodeException e) {
                // 校验产生异常 进行异常处理
                myAuthenticationFailHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,e);
                return;
            }
        }
        // 继续后面的过滤器
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }

    private void validate(ServletWebRequest servletWebRequest) throws ValidateCodeException, ServletRequestBindingException {

        ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, SESSION_KEY);

        String codeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "imageCode");
        if (StringUtils.isBlank(codeInRequest)) {
            throw new ValidateCodeException("验证码的值不能为空");
        }
        if (codeInSession == null) {
            throw new ValidateCodeException("验证码不存在");
        }
        if (codeInSession.isExpire()) {
            sessionStrategy.removeAttribute(servletWebRequest, SESSION_KEY);
            throw new ValidateCodeException("验证码已经过期");
        }
        if (!codeInSession.getCode().equalsIgnoreCase(codeInRequest)) {
            throw new ValidateCodeException("验证码不匹配");
        }
        // 验证通过，从session中移除验证码
        sessionStrategy.removeAttribute(servletWebRequest, SESSION_KEY);
    }
}
